package ldh.maker.handle;

import javafx.application.Platform;
import javafx.scene.control.*;
import javafx.scene.control.TextArea;
import javafx.scene.paint.Color;
import javafx.util.Callback;
import ldh.maker.component.CodeTextArea;
import ldh.maker.component.ContentUi;
import ldh.maker.component.TableUi;
import ldh.maker.constants.TreeNodeTypeEnum;
import ldh.maker.database.TableInfo;
import ldh.maker.db.TreeNodeDb;
import ldh.maker.util.*;
import ldh.maker.vo.DBConnectionData;
import ldh.maker.vo.TreeNode;
import org.fxmisc.flowless.VirtualizedScrollPane;

import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by ldh on 2017/2/19.
 */
public class ProjectTreeHandle {

    private TreeView<TreeNode> projectTree;
    private TabPane contentPane;

    public ProjectTreeHandle(TreeView<TreeNode> projectTree, TabPane contentPane) {
        this.projectTree = projectTree;
        this.contentPane = contentPane;

        initEventHandle();
    }

    private void initEventHandle() {

        projectTree.setCellFactory(new Callback<TreeView<TreeNode>,TreeCell<TreeNode>>(){
            @Override
            public TreeCell<TreeNode> call(TreeView<TreeNode> p) {
                return new TreeCell<TreeNode>() {
                    @Override
                    public void updateItem(TreeNode item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty) {
                            setText(null);
                            setGraphic(null);
                        } else {
                            if (item != null) {
                                setText(item.getText());
                                setGraphic(getTreeItem().getGraphic());
                            }
                        }
                    }
                };
            }
        });

        projectTree.setOnMouseClicked(e->{
            if (e.getClickCount() != 2) return;
            TreeItem<TreeNode> treeItem = (TreeItem) projectTree.getSelectionModel().getSelectedItem();
            if (treeItem == null)  return;
            TreeNode treeData = treeItem.getValue();
            if (treeData.getType() == TreeNodeTypeEnum.PROJECT) {
                if (treeItem.getChildren().size() > 0) return;
                if (treeData.getChildren().size() == 0) {
                    initNodeChildren(treeItem);
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.DATABASE) {
                if (treeItem.getChildren().size() > 0) return;
                if (treeData.getChildren().size() == 0) {
                    initNodeChildren(treeItem);
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.DB_CONNECTION) {
                if (treeItem.getChildren().size() > 0) return;
                if (treeData.getChildren().size() == 0) {
                    initDbs(treeItem);
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.DB) {
                if (treeItem.getChildren().size() > 0) {
                    selectTab(treeItem.getValue());
                    boolean isHave = false;
                    for (Tab tab : contentPane.getTabs()) {
                        if (tab.getText().equals(treeItem.getValue().getText())) {
                            isHave = true;
                            break;
                        }
                    }
                    if (!isHave) {
                        Platform.runLater(()->{
                            initTabTable(treeItem);
                        });
                    }
                    return;
                }
                if (treeData.getChildren().size() == 0) {
                    initTables(treeItem);
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.DB_TABLE) {
                selectTab(treeItem.getValue().getParent());
                if (treeItem.getChildren().size() > 0) {
                    return;
                }
                if (treeData.getChildren().size() == 0) {
                    initColumn(treeItem);
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.CODE) {
                if (treeItem.getChildren().size() > 0) return;
                if (treeData.getChildren().size() == 0) {
                    codeRefresh(treeItem.getParent());
                }
            } else if (treeData.getType() == TreeNodeTypeEnum.JAVA_FILE) {
                showCode(treeItem);
            }
        });
    }

    private void selectTab(TreeNode treeNode) {
        for (Tab tab : contentPane.getTabs()) {
            if (tab.getText().equals(treeNode.getText())) {
                contentPane.getSelectionModel().select(tab);
                break;
            }
        }
    }

    private void initNodeChildren(final TreeItem<TreeNode> treeItem) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TreeNodeDb.initNode(treeItem);
//                    if (treeItem.getChildren().size() == 0) {
//                        DialogUtil.show(Alert.AlertType.INFORMATION, "提醒", "节点下面没有数据");
//                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    private void initDbs(TreeItem<TreeNode> treeItem) {
        DBConnectionData data = (DBConnectionData) treeItem.getValue().getData();
        Connection connection = data.getConnection();
        if (connection == null) {
            connection = ConnectionFactory.getConnection(data);
            data.setConnection(connection);
        }
//        TreeViewGraphicUtil.setTreeItemProjectGraphic(treeItem);
        DatabaseMetaData meta = null;
        try {
            meta = connection.getMetaData();
            ResultSet schemasRS = meta.getCatalogs();
            List<String> dbNames = new ArrayList<>();
            while (schemasRS.next()) {
                String schema = schemasRS.getString("TABLE_CAT");
                if (schema == null || schema.length() == 0){
                    continue;
                }
                dbNames.add(schema);
            }
            initDbsUi(treeItem.getValue(), dbNames);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    private void initDbsUi(TreeNode treeNode, List<String> dbNames) {
        TreeItem<TreeNode> parentTreeItem = (TreeItem) projectTree.getSelectionModel().getSelectedItem();
        for (String db : dbNames) {
            TreeNode tn = new TreeNode(TreeNodeTypeEnum.DB, db, treeNode);
            tn.setData(db);
            treeNode.getChildren().add(tn);
            TreeItem<TreeNode> treeItem = new TreeItem<>(tn);
            TreeNodeDb.setGraphic(treeItem);
            parentTreeItem.getChildren().add(treeItem);
            parentTreeItem.setExpanded(true);
        }
    }

    private void initTables(TreeItem<TreeNode> treeItem) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                DBConnectionData data = (DBConnectionData) treeItem.getValue().getParent().getData();
                String db = treeItem.getValue().getData().toString();
                Connection connection = ConnectionFactory.getConnection(data, db);
                TableInfo tableInfo = new TableInfo(connection, db, treeItem);
                DbInfoFactory.getInstance().put(treeItem.getValue().getParent().getId() + "_" + db, tableInfo);
                Platform.runLater(()->{
//                    initTablesUi(treeItem.getValue(), tableInfo);
                    initTabTable(treeItem);
                });
                Platform.runLater(()->{
                    initTablesUi(treeItem.getValue(), tableInfo);
                });
            }
        }).start();

    }

    private void initTablesUi(TreeNode treeNode, TableInfo tableInfo) {
        TreeItem<TreeNode> parentTreeItem = (TreeItem) projectTree.getSelectionModel().getSelectedItem();
        for (String table : tableInfo.getTables().keySet()) {
            TreeNode tn = new TreeNode(TreeNodeTypeEnum.DB_TABLE, table, treeNode);
            tn.setData(table);
            treeNode.getChildren().add(tn);
            TreeItem<TreeNode> treeItem = new TreeItem<>(tn);
            TreeNodeDb.setGraphic(treeItem);
            parentTreeItem.getChildren().add(treeItem);

        }
        parentTreeItem.setExpanded(true);
    }

    private void initColumn(TreeItem<TreeNode> treeItem) {
        new Thread(()->{
            DBConnectionData data = (DBConnectionData) treeItem.getValue().getParent().getParent().getData();
            String db = treeItem.getParent().getValue().getData().toString();
            Connection connection = ConnectionFactory.getConnection(data, db);

            PreparedStatement ps = null;
            try {
                String table = treeItem.getValue().getData().toString();
                ps = connection.prepareStatement("select * from " +  table);
                ResultSet rs = ps.executeQuery();
                ResultSetMetaData rsme = rs.getMetaData();
                int columnCount = rsme.getColumnCount();
                List<String> columnNames = new ArrayList<>();
                for (int i = 1; i < columnCount ; i++) {
                    columnNames.add(rsme.getColumnName(i));
                }
                initColumnUi(treeItem, columnNames);
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                ConnectionFactory.close(ps);
                ConnectionFactory.close(connection);
            }

        }).start();
    }

    private void initColumnUi(TreeItem<TreeNode> treeItem, List<String> columnNames) {
        for (String column : columnNames) {
            TreeNode tn = new TreeNode(TreeNodeTypeEnum.DB_COLUMN, column, treeItem.getValue());
            tn.setData(column);
            treeItem.getValue().getChildren().add(tn);
            TreeItem<TreeNode> ti = new TreeItem<>(tn);
            treeItem.getChildren().add(ti);
        }
        treeItem.setExpanded(true);
    }

    private void initTabTable(TreeItem<TreeNode> treeItem) {
        Tab tab = new Tab(treeItem.getValue().getText() + "数据库代码生成");
        ContentUi contentUi = UiUtil.getContentUi();
        contentUi.setTreeItem(treeItem);

        tab.setContent(contentUi);
        contentPane.getTabs().add(tab);
        contentPane.getSelectionModel().select(tab);
    }

    public static void codeRefresh(TreeItem<TreeNode> treeItem) {
        String path = FileUtil.getSourceRoot();
        String codeJava = path + "/code/" + treeItem.getValue().getText();
//        String codeJava = path + "/code/" + treeItem.getValue().getText() + "/src/main/java";
//        String resourceJava = path + "/code/" + treeItem.getValue().getText() + "/src/main/resources";
//        String resources= path + "/code/" + treeItem.getValue().getText() + "/src/main/webapp";
        TreeItem<TreeNode> root = treeItem;
        for (TreeItem<TreeNode> ti : treeItem.getChildren()) {
            if (ti.getValue().getType() == TreeNodeTypeEnum.CODE) {
                root = ti;
            }
        }
        final TreeItem<TreeNode> root1 = root;
        Platform.runLater(()->{
            FileUtil.loadFileTree(codeJava, root1, true);
//            FileUtil.loadFileTree(resourceJava, root1);
//            FileUtil.loadFileTree(resources, root1);
        });
    }

    private void showCode(TreeItem<TreeNode> treeItem) {
        String file = treeItem.getValue().getData().toString();
        for (Tab tab : contentPane.getTabs()) {
            if (tab.getText().equals(treeItem.getValue().getText())) {
                contentPane.getSelectionModel().select(tab);
                return;
            }
        }
        Tab tab = new Tab(treeItem.getValue().getText());
        new Thread(()->{
            String fileContent = null;
            try {
                fileContent = FileUtil.loadFile(file);
                boolean isXml = file.endsWith("xml");
                CodeTextArea textArea = new CodeTextArea(fileContent, isXml);
                tab.setContent(new VirtualizedScrollPane<>(textArea));
                Platform.runLater(()->{
                    contentPane.getTabs().add(tab);
                    contentPane.getSelectionModel().select(tab);
                });
            } catch (IOException e) {
                e.printStackTrace();
            }

        }).start();
    }
}
